package com.kefu.chat.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HtmlUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.opensearch.sdk.generated.commons.OpenSearchResult;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Lists;
import com.kefu.chat.http.NlpClient;
import com.kefu.chat.http.RobotAskParam;
import com.kefu.chat.http.RobotAskResult;
import com.kefu.chat.http.RobotNearestParam;
import com.kefu.chat.model.*;
import com.kefu.chat.util.ChatConstant;
import com.kefu.chat.vo.ChatAdminParam.AdminRobotAskP;
import com.kefu.chat.vo.ChatAdminParam.AdminRobotAskR;
import com.kefu.chat.vo.ChatUserParam.UserRobotAskP;
import com.kefu.chat.vo.ChatUserParam.UserRobotAskR;
import com.kefu.chat.vo.ChatUserParam.UserRobotTipsP;
import com.kefu.common.context.KefuContext;
import com.kefu.common.util.JacksonUtil;
import com.kefu.common.util.StreamUtil;
import com.kefu.framework.config.KefuProperties;
import com.kefu.robot.model.*;
import com.kefu.robot.service.*;
import com.kefu.robot.utils.AidataUtil;
import com.kefu.robot.service.RobotAidataRecordingService;
import com.kefu.robot.vo.OpenSearchResultToBeanVo;
import com.kefu.robot.vo.RobotAidataUtilSearch;
import com.kefu.robot.vo.RobotDocNodeItemVo;
import com.kefu.robot.vo.RobotDocVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
public class ChatRobotService {
    @Autowired
    private ChatCacheService chatCacheService;
    @Autowired
    private ChatSessionMsgService chatSessionMsgService;
    @Autowired
    private ChatChannelService chatChannelService;
    @Autowired
    private RobotInfoService robotInfoService;
    @Autowired
    private RobotUnknownService robotUnknownService;
    @Autowired
    private RobotStudyService robotStudyService;
    @Autowired
    private NlpClient nlpClient;
    @Autowired
    private RobotDocNodeService robotDocNodeService;
    @Autowired
    RobotSynonymService robotSynonymService;
    @Autowired
    KefuProperties kefuProperties;
    @Autowired
    private RobotConnectRelService robotConnectRelService;
    @Autowired
    private AidataUtil aidataUtil;
    @Autowired
    private RobotAidataRecordingService robotAidataRecordingService;
    @Autowired
    private RobotAidataDocService robotAidataDocService;
    @Autowired
    private RobotAidataInfoService robotAidataInfoService;


    public UserRobotAskR userRobotAsk(UserRobotAskP param) {
        UserRobotAskR result = new UserRobotAskR();
        param.setQuestion(param.getQuestion().trim());
        ChatUser user = chatCacheService.getUser(param.getUserId());
        //没有初始化，人工状态，直接return
        if (user == null || user.getStatus() == ChatConstant.user_status_online) {
            result.setStatus(user == null ? 0 : user.getStatus());
            return result;
        }
        RobotInfo robotInfo = robotInfoService.getByRobotNo(user.getTenantId(), param.getRobotNo());
        if (robotInfo == null) {
            return result;
        }
        ChatChannel chatChannel = chatChannelService.getFromId(user.getChannelId());
        //转人工关键字
        if (Objects.equals(chatChannel.getKeywordMode(), 1)) {
            List<RobotConnectRel> robotConnectRelList = robotConnectRelService.getList(user.getTenantId());
            if (null != robotConnectRelList && robotConnectRelList.size() > 0) {
                boolean matchConnect = false;
                for (RobotConnectRel rel : robotConnectRelList) {
                    if (1 == rel.getMatchType()) {
                        // 包含匹配
                        if (param.getQuestion().contains(rel.getConnectContent())) {
                            matchConnect = true;
                            break;
                        }
                    } else if (2 == rel.getMatchType()) {
                        //完全匹配
                        if (param.getQuestion().equals(rel.getConnectContent())) {
                            matchConnect = true;
                            break;
                        }
                    }
                }
                if (matchConnect) {
                    //命中转人工关键字
                    result.setStatus(-1);
                    ChatSessionMsg msgLog = ChatSessionMsg.builder().id(IdUtil.simpleUUID()).userId(user.getUserId()).sessionId(user.getSessionId()).tenantId(user.getTenantId()).sender(user.getUserId()).senderName(user.getUserName())
                            .senderType(ChatConstant.msg_sender_user).receiveType(ChatConstant.msg_sender_robot).receive(robotInfo.getRobotNo() + "").msgType(1).msgContent(param.getQuestion())
                            .msgTime(System.currentTimeMillis()).robotNo(robotInfo.getRobotNo()).build();
                    chatSessionMsgService.insertSessionMsg(msgLog);
                    return result;
                }
            }
        }
        long robotTime = System.currentTimeMillis();
        //首次咨询，插入机器人集合，更新用户状态
        if (user.getStatus() == ChatConstant.user_status_offline) {
            chatCacheService.addRobotSet(user.getTenantId(), user.getSessionId());
            user.setStatus(ChatConstant.user_status_robot);
            user.setRobotNo(robotInfo.getRobotNo());
            user.setRobotName(robotInfo.getRobotName());
            user.setRobotTime(robotTime);
            if (user.getStartTime() == 0) user.setStartTime(user.getRobotTime());
            chatCacheService.setUser(user);
        }
        //多轮问题节点
        boolean hasNode = false;
        if (StrUtil.isNotBlank(param.getNodeId())) {
            if (StrUtil.isNotBlank(param.getQuestion()) && StrUtil.isBlank(param.getItemId())) {

                List<RobotDocNodeItemVo> list = robotDocNodeService.selectListVoByNodeId(param.getNodeId());
                List<Object[]> checkValues = list.stream().flatMap(vo -> {
                    RobotDocNodeItem item = vo.getNodeItem();
                    Float threshold = item.getThreshold() == null ? 0.50F : item.getThreshold().floatValue();
                    return Stream.concat(vo.getSynonyms().stream().map(sys -> new Object[]{sys.getItemId(), sys.getQuestion(), threshold})
                            , Stream.of(new Object[][]{{item.getItemId(), item.getItemContent(), threshold}}));
                }).collect(Collectors.toList());
                RobotNearestParam nearestParam = new RobotNearestParam();
                nearestParam.setQuestion(param.getQuestion());
                nearestParam.setQuestionList(checkValues.stream().map(question -> (String) question[1]).collect(Collectors.toList()));
                nearestParam.setSize(checkValues.size());
                List<Map.Entry<Integer, Float>> scopList = nlpClient.nearest(nearestParam);
                StreamUtil.stream(scopList).sorted(Comparator.comparing(Map.Entry<Integer, Float>::getValue).reversed())
                        .filter(entry -> entry.getValue() >= (Float) checkValues.get(entry.getKey())[2])
                        .findFirst()
                        .ifPresent(entry -> {
                            param.setItemId((String) checkValues.get(entry.getKey())[0]);
                        });
            }
            if (StrUtil.isNotBlank(param.getItemId())) {
                RobotDocNode docNode = robotDocNodeService.getNextNode(param, user);
                if (docNode != null) {
                    hasNode = true;
                    result.setDocNode(docNode);
                    result.setDocId(docNode.getDocId());
                    result.setAnswerType(1);
                    result.setDocPattern(1);

                }
            }
        }

        //机器人问答
        boolean studyStatus = false;
        String studyQuestion = "";
        if (!hasNode) {
            //输入数字序号转换
            String question = param.getQuestion();
            if (NumberUtil.isInteger(question) && Integer.parseInt(question) <= 5) {
                ChatData chatData = chatCacheService.getData(user.getSessionId());
                if (chatData != null && StrUtil.isNotBlank(chatData.getRobotSuggest())) {
                    List<RobotDocVo> suggestList = JacksonUtil.toBean(chatData.getRobotSuggest(), new TypeReference<List<RobotDocVo>>() {
                    });
                    if (suggestList != null && suggestList.size() >= Integer.parseInt(question)) {
                        //输入的数字在上一次推荐问题的序号范围，把参数设置为用户点击某个词条
                        param.setDocId(suggestList.get(Integer.parseInt(question) - 1).getDocId());
                        question = suggestList.get(Integer.parseInt(question) - 1).getQuestion();
                        param.setClick(1);
                    }
                }
            }
            //同义词替换为标准问法
            List<RobotSynonym> synonymList = robotSynonymService.getList(user.getTenantId());
            if (CollUtil.isNotEmpty(synonymList)) {
                boolean breakFlag = false;
                for (RobotSynonym synonym : synonymList) {
                    String[] array = synonym.getQuestion().split(",");
                    for (String similar : array) {
                        if (question.contains(similar)) {
                            question = question.replace(similar, synonym.getTitle());
                            breakFlag = true;
                            break;
                        }
                    }
                    if (breakFlag) {
                        break;
                    }
                }
            }


            //请求机器人接口
            RobotAskParam robotAskParam = BeanUtil.toBean(param, RobotAskParam.class);
            robotAskParam.setQuestion(question);
            robotAskParam.setTenantId(user.getTenantId());
            robotAskParam.getRobotList().add(param.getRobotNo());
            robotAskParam.getRobotList().add(0);//公共知识库
            robotAskParam.getRobotList().add(-1);//自定义寒暄
            robotAskParam.setGreetBase(robotInfo.getGreetBase());
            robotAskParam.setGreetNetwork(robotInfo.getGreetNetwork());
            RobotAskResult robotAskResult = nlpClient.robotAsk(robotAskParam);
            log.info("咨询机器人:{}, {}", robotAskParam, robotAskResult);
            BeanUtil.copyProperties(robotAskResult, result, CopyOptions.create().ignoreNullValue());
            //上次提问是引导回答，本次点击后有直接答案的，上次问题智能学习本次词条
            if (param.getClick() == 1 && StrUtil.isNotBlank(result.getDocId())) {
                ChatData chatData = chatCacheService.getData(user.getSessionId());
                if (chatData != null && chatData.getRobotAnswerType() == 2) {
                    studyStatus = true;
                    studyQuestion = chatData.getUserMsgContent();
                }
            }

            // 设置未知回答话术
            // nlp无法回答先请求阿里AI大模型，大模型也无法回答，在设置未知回答话术
            if (result.getAnswerType() == 0) {
                //Ai大模型
                if (Objects.equals(robotInfo.getAidataStatus(), 1) && StrUtil.isNotBlank(robotInfo.getAidataId())) {
                    RobotAidataInfo aidataInfo = robotAidataInfoService.getById(robotInfo.getAidataId());
                    if (Objects.equals(aidataInfo.getState(), 1)) {
                        String aidataId = robotInfo.getAidataId();
                        OpenSearchResult search = aidataUtil.search(RobotAidataUtilSearch.builder().session(user.getSessionId()).category(aidataId).question(param.getQuestion()).roleName(robotInfo.getRobotName()).build());
                        //添加请求记录
                        RobotAidataRecording robotAidataRecording = new RobotAidataRecording();
                        robotAidataRecording.setQuestion(param.getQuestion());
                        robotAidataRecording.setAnswer(JSONUtil.toJsonStr(search));
                        robotAidataRecording.setSession(user.getSessionId());
                        robotAidataRecording.setCreateTime(DateUtil.current());
                        robotAidataRecording.setCreateUser(user.getUserId());
                        robotAidataRecording.setTenantId(user.getTenantId());
                        robotAidataRecording.setType(1);
                        robotAidataRecordingService.save(robotAidataRecording);
                        if (StrUtil.isNotBlank(search.getResult())) {
                            OpenSearchResultToBeanVo openSearchResult = JSONUtil.toBean(search.getResult(), OpenSearchResultToBeanVo.class);
                            if (CollUtil.isNotEmpty(openSearchResult.getData())) {
                                if (CollUtil.isNotEmpty(openSearchResult.getData().get(0).getReference())) {
                                    OpenSearchResultToBeanVo.Reference reference = openSearchResult.getData().get(0).getReference().get(0);
                                    if (StrUtil.isNotBlank(reference.getId())) {
                                        result.setDocId(reference.getId());
                                        RobotAidataDoc aidataDoc = robotAidataDocService.getOne(Wrappers.lambdaQuery(RobotAidataDoc.class)
                                                .eq(RobotAidataDoc::getDocId, reference.getId()));
                                        if (aidataDoc != null) {
                                            result.setQuestion(aidataDoc.getName());
                                        }
                                        if (StrUtil.isNotBlank(openSearchResult.getData().get(0).getAnswer())) {
                                            result.setAnswer(openSearchResult.getData().get(0).getAnswer().replace("<|im_end|>",""));;
                                        }
                                        result.setMsgType(3);
                                        result.setAnswerType(-4);
                                    }
                                }
                            }
                        }
                    }
                }
                if (result.getAnswerType() != -4) {
                    result.setAnswer(chatChannel.getRobotUnknownMsg());
                }
            }
            //命中多轮问题词条
            if (result.getDocPattern() == 1 && StrUtil.isNotBlank(result.getDocId())) {
                param.setDocId(result.getDocId());
                RobotDocNode docNode = robotDocNodeService.getFirstNode(param, user);
                result.setDocNode(docNode);

            }
        }
        //插入聊天记录
        ChatSessionMsg msgLog = ChatSessionMsg.builder().id(IdUtil.simpleUUID()).userId(user.getUserId()).sessionId(user.getSessionId()).tenantId(user.getTenantId()).sender(user.getUserId()).senderName(user.getUserName())
                .senderType(ChatConstant.msg_sender_user).receiveType(ChatConstant.msg_sender_robot).receive(robotInfo.getRobotNo() + "").msgType(1).msgContent(param.getQuestion())
                .msgTime(robotTime).robotNo(robotInfo.getRobotNo()).build();
        chatSessionMsgService.insertSessionMsg(msgLog);
        ChatSessionMsg robotLog = BeanUtil.toBean(msgLog, ChatSessionMsg.class);
        robotLog.setId(IdUtil.simpleUUID());
        robotLog.setSender(robotInfo.getRobotNo() + "");
        robotLog.setSenderName(robotInfo.getRobotName());
        robotLog.setSenderType(ChatConstant.msg_sender_robot);
        robotLog.setReceiveType(ChatConstant.msg_sender_user);
        robotLog.setReceive(user.getUserId());
        robotLog.setMsgType(result.getMsgType() == null ? 3 : result.getMsgType());
        robotLog.setMsgContent(result.getAnswer());
        robotLog.setAnswerType(result.getAnswerType());
        robotLog.setMsgTime(System.currentTimeMillis());
        robotLog.setRobotNo(robotInfo.getRobotNo());
        if (result.getAnswerType() == 1) {
            robotLog.setDocId(result.getDocId());
            robotLog.setDocPattern(result.getDocPattern());
        }
        if (CollUtil.isNotEmpty(result.getSuggestList())) {
            robotLog.setRobotSuggest(JacksonUtil.toString(result.getSuggestList()));
        }
        if (result.getDocNode() != null) {
            robotLog.setDocNode(JacksonUtil.toString(result.getDocNode()));
        }
        chatSessionMsgService.insertSessionMsg(robotLog);
        result.setMsgId(robotLog.getId());
        //插入未知问题
        if (result.getAnswerType() == 0) {
            RobotUnknown model = BeanUtil.toBean(user, RobotUnknown.class);
            model.setId(IdUtil.simpleUUID());
            model.setQuestion(param.getQuestion());
            model.setRobotNo(param.getRobotNo());
            model.setCreateTime(System.currentTimeMillis());
            ThreadUtil.execute(() -> robotUnknownService.save(model));
        }
        //插入智能学习
        if (studyStatus && StrUtil.isAllNotBlank(studyQuestion, result.getDocId())) {
            RobotStudy model = BeanUtil.toBean(user, RobotStudy.class);
            model.setId(IdUtil.simpleUUID());
            model.setQuestion(studyQuestion);
            model.setRobotNo(param.getRobotNo());
            model.setCreateTime(System.currentTimeMillis());
            model.setDocId(result.getDocId());
            model.setDocQuestion(result.getQuestion());
            ThreadUtil.execute(() -> robotStudyService.save(model));
        }
        //移动端，机器人词条富文本处理
        String answer = result.getAnswer();
        String docId = result.getDocId();
        if (param.getCleanHtmlTag() == 1 && StrUtil.isNotBlank(docId) && StrUtil.isNotBlank(answer)) {
            result.setAnswer(HtmlUtil.cleanHtmlTag(answer));
            if (answer.contains("http")) {
                result.setHtmlUrl(kefuProperties.getDomain() + "/chat_online/question?docId=" + docId + "&userId=" + param.getUserId());
            }
        }
        return result;
    }

    public List<RobotDocVo> robotTips(UserRobotTipsP param) {
        List<RobotDocVo> result = new ArrayList<>();
        ChatUser user = chatCacheService.getUser(param.getUserId());
        //没有初始化，人工或者排队状态，直接return
        if (user == null || user.getStatus() == ChatConstant.user_status_online || user.getStatus() == ChatConstant.user_status_wait) {
            return result;
        }
        //请求机器人接口
        RobotAskParam robotAskParam = BeanUtil.toBean(param, RobotAskParam.class);
        robotAskParam.setTenantId(user.getTenantId());
        robotAskParam.getRobotList().add(param.getRobotNo());
        robotAskParam.getRobotList().add(0);//公共知识库
        robotAskParam.getRobotList().add(-1);//自定义寒暄
        robotAskParam.setTips(1);
        RobotAskResult robotAskResult = nlpClient.robotAsk(robotAskParam);
        List<RobotDocVo> emptyList = Lists.newArrayList();
        return robotAskResult == null ? emptyList : robotAskResult.getSuggestList();
    }

    public AdminRobotAskR adminRobotAsk(AdminRobotAskP param) {
        AdminRobotAskR result = new AdminRobotAskR();
        //请求机器人接口
        RobotAskParam robotAskParam = BeanUtil.toBean(param, RobotAskParam.class);
        robotAskParam.setTenantId(KefuContext.getKefuContext().getTenantId());
        robotAskParam.setTips(1);
        RobotAskResult robotAskResult = nlpClient.robotAsk(robotAskParam);
        BeanUtil.copyProperties(robotAskResult, result, CopyOptions.create().ignoreNullValue());
        return result;
    }
}
